/**
* @file    BinInput.h
* @brief   Binary array data input
* @date    2014/02
* @version
* Copyright (c)
*/

#ifndef BinInput_h__
#define BinInput_h__

#include <fstream>
#include <list>
#include <string>
#include <vector>

#include "TypeCast.h"

struct transfer {
    transfer() { from = to = 0; mult = 1.0; };
    transfer(const UGINT64 _from, const UGINT64 _to, const double _mult) {
        from = _from; to = _to; mult = _mult;
    };

    UGINT64 from, to;
    double mult;
};

class PropArray {
public:
    PropArray();
    PropArray(const PropArray& src);
    ~PropArray();
    void operator=(const PropArray& src);

    double operator[](const UGINT64 i) const {
        if (type == 'd') return fdata[i];
        else return (double)idata[i];
    };

    void Clear();
    bool is_empty() const { return length==0; }

    bool ReMap(const UGINT64 Net_size, const UGINT64 Pre_Net_size, const std::vector<transfer>& Moves);

    char    type; // 'i' or 'd' (int or double)
    UGINT64 length;
    int*    idata;
    double* fdata;

    bool on_grid;

    char    time_type; // 'd' or 't' (date or time)
    double  time;

    double  Max, Min, Avg;

    std::string name;
    std::string unit;
};

struct Name_Loc {
    char type = 'u';
    UGINT64 length = 0;

    bool on_grid = false;

    char   time_type;
    double time;

    double Max, Min, Avg;

    std::string name;
    std::string unit;

    UGINT64 fcount = 0;
    UGINT64 offset = 0;
};

// 油藏网格数据读取
class BinReader {
public:
    BinReader() {};
    BinReader(const std::string& _casename);
    ~BinReader() {};

    // Before calling accessing subroutines, scan binary files first
    void Scan(const std::string& _casename);

    // return mismatch
    int  ReMap(const double* GridInfo_in, const int* SubregInfo_in, const int* Host_map_in, const int* Gross2Net_in, const int* Net2Gross_in);

    void Clear();

    UGINT64 NStep() const { return dym_props.size(); };

    // return if find
    bool GetDynamicData(const UGINT64 tstep, const std::string& name, PropArray& a, const bool remap = false) const;
    bool GetStaticData(const std::string& name, PropArray& a, const bool remap = false) const;

    UGINT64 NetSize() const { return Net2Gross.size(); }; // = GridInfo[8]
    UGINT64 GrossSize() const { return Gross2Net.size(); }; // = GridInfo[2]

    UGINT64 GridType() const { return GridInfo[0]; };  // 0-Cartesian, 1-Stage, 2-CPG, 3-PEBI
    UGINT64 PoroLvl()  const { return GridInfo[1]; };

    void GetAxisOffset(double& x0, double& y0, double& d0) const { x0 = AxisOffset[0]; y0 = AxisOffset[1]; d0 = AxisOffset[2]; }

    // IJk grid info
    UGINT64 SGridNI()  const { return GridInfo[3]; };
    UGINT64 SGridNJ()  const { return GridInfo[4]; };
    UGINT64 SGridNK()  const { return GridInfo[5]; };

    // IJk grid info: base gird & fine grid
    UGINT64 NumBaseGrid() const { return GridInfo[2] - GridInfo[6] - GridInfo[7]; };
    UGINT64 NumActBaseGrid() const { return GridInfo[9] + GridInfo[11] * (GridInfo[1] - 1); };
    UGINT64 NumFLvActBaseGrid() const { return GridInfo[9]; };
    UGINT64 NumMtxActBaseGrid() const { return GridInfo[11]; };

    UGINT64 NumFineGrid() const { return GridInfo[6]; };
    UGINT64 NumActFineGrid() const { return GridInfo[10] + GridInfo[12] * (GridInfo[1] - 1); };
    UGINT64 NumFLvActFineGrid() const { return GridInfo[10]; };
    UGINT64 NumMtxActFineGrid() const { return GridInfo[12]; };

    // Embedded fracture
    UGINT64 NumEmdfFace() const { return GridInfo[7]; };
    UGINT64 NumActEmdfFace() const { return GridInfo[13]; };

    // PEBI grid info
    UGINT64 PGridNG()  const { return GridInfo[14]; };
    UGINT64 PGridNLy() const { return GridInfo[15]; };
    UGINT64 PGridNV()  const { return GridInfo[18]; };

    UGINT64 UnitType() const { return GridInfo[19]; };

    // gross to net grid mapping and net to gross grid mapping
    std::vector<int> Gross2Net;
    std::vector<int> Net2Gross;

    UGINT64 GridInfo[32] = { 0 };
    double AxisOffset[3] = { 0 };

    std::vector<std::vector<Name_Loc>> dym_props; // 第N个数组存第N个时间步的所有属性
    std::vector<Name_Loc> stat_props;
    std::string casename;

private:
    UGINT64 origin_net_size = 0;
    UGINT64 origin_GridInfo[32] = { 0 };
    std::vector<int> origin_Gross2Net;
    std::vector<transfer> Moves;
};

#endif // BinInput_h__
